package com.springcloudalibaba.apiPay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.springcloudalibaba.bclass.util.LoggerUtil;
import com.springcloudalibaba.bclass.util.RequestUtil;
import com.springcloudalibaba.apiPay.configurer.properties.AdvancePaymentProperties;
import com.springcloudalibaba.apiPay.configurer.properties.AdvancePaymentPropertiesConfig;
import com.springcloudalibaba.apiPay.event.PayCallbackFailEvent;
import com.springcloudalibaba.apiPay.event.PayCallbackSuccessEvent;
import com.springcloudalibaba.apiPay.service.WeChatPayCallbackService;
import com.springcloudalibaba.apiPay.util.WxPayUtil;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import java.text.MessageFormat;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @描述: 阿里巴巴支付回调服务
 * @作者: lixing
 * @日期 2021/7/9 8:22
 */
@Service
public class WeChatPayCallbackServiceImpl implements WeChatPayCallbackService {
    /**
     * 预支付信息
     */
    @Autowired
    private AdvancePaymentPropertiesConfig advancePaymentPropertiesConfig;

    /** 容器上下文对象 */
    @Resource
    private ApplicationContext applicationContext;

    /**
     * @描述 支付成功异步回调
     * @作者 lixing
     * @日期 2021/7/9 8:24
     * @Param [request]
     *
     * 支付结果通知: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
     * {
     *  "result_code": "SUCCESS",                         // 业务结果:SUCCESS/FAIL
     *  "return_code": "SUCCESS"                          // 返回状态码:SUCCESS/FAIL,此字段是通信标识，非交易标识，交易是否成功需要查看result_code来判断
     *  "return_msg": ""                                  // 返回信息
     *  "err_code": "",                                   // 错误代码
     *  "err_code_des": "",                               // 错误代码描述
     * 	"transaction_id": "4200001162202107099957876259", // 微信支付订单号
     * 	"nonce_str": "KEWSKF4JreEo0yhDCQ1jBpLygg1GuTOj",  // 随机字符串，不长于32位
     * 	"bank_type": "COMM_CREDIT",                       // 付款银行
     * 	"openid": "oVRIQ47eUZSk2FL9UFweZn1chEYk",         // 用户在商户appid下的唯一标识
     * 	"sign": "1EC265BE32A08D65E8FE0B3526DA4624",       // 签名
     * 	"fee_type": "CNY",                                // 货币种类，货币类型，符合ISO4217标准的三位字母代码，默认人民币：CNY
     * 	"mch_id": "1611059987",                           // 微信支付分配的商户号
     * 	"cash_fee": "1",                                  // 现金支付金额订单现金支付金额
     * 	"out_trade_no": "100000_10000016258120350601",    // 商户订单号
     * 	"appid": "wx18cda9dfbce1d8b8",                    // 微信分配的小程序ID
     * 	"total_fee": "1",                                 // 订单金额，单位为分
     * 	"trade_type": "JSAPI",                            // 交易类型:JSAPI、NATIVE、APP
     * 	"time_end": "20210709142726",                     // 支付完成时间
     * 	"is_subscribe": "N",                              // 用户是否关注公众账号，Y-关注，N-未关注
     * 	"attach": ""                                      // 商家数据包，原样返回
     * }
     */
    @Override
    public void notifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 回调参数
        String resXmlStr = RequestUtil.getRequestParamForWeChat(request);
        Map<String, String> resultMap = WxPayUtil.xmlToMap(resXmlStr);
        // 业务结果
        String resultCode = resultMap.get("result_code");
        // 返回状态码
        String returnCode = resultMap.get("return_code");
        if (WXPayConstants.FAIL.equals(resultCode) || WXPayConstants.FAIL.equals(returnCode)) {
            /*
             * 通知微信
             */
            SortedMap<String,String> reqMap = new TreeMap<>();
            reqMap.put("return_code", WXPayConstants.FAIL);
            reqMap.put("return_msg", resultMap.get("return_msg"));
            String reqXml = WXPayUtil.mapToXml(reqMap);
            response.getWriter().write(reqXml);
        } else {
            // 订单号
            String orderId = resultMap.get("out_trade_no");
            // 支付金额
            String totalFee = resultMap.get("total_fee");
            // 用户在商户appid下的唯一标识
            String openid = resultMap.get("openid");
            // 支付完成时间
            String timeEnd = resultMap.get("time_end");
            // 商家数据包
            String attach = resultMap.get("attach");
            JSONObject attachObj = JSONObject.parseObject(attach);
            /*
             * 根据 businessType 获取 相关参数
             */
            String productId = attachObj.getString("productId");
            long userId = attachObj.getLong("userId");
            Integer client = attachObj.getInteger("client");
            String sourceFrom = attachObj.getString("sourceFrom");
            AdvancePaymentProperties advancePaymentProperties = null;// advancePaymentPropertiesConfig.getParamsByBusinessType(ClientEnum.WECHAT.getClient(), productId, userId, sourceFrom);
            /*
             * 验签
             */
            boolean isResponseSignatureValid = WxPayUtil.isSignatureValid(resultMap, advancePaymentProperties.getWechatKey(), WXPayConstants.SignType.MD5);
            if (isResponseSignatureValid) {
                LoggerUtil.error(MessageFormat.format("【微信】买家：{0} 于 {1} 支付金额 {2} 异步回调验签成功，订单编号：{3} 交易状态：{4}", openid, timeEnd, totalFee, orderId, returnCode));
                /*
                 * 异步更新订单状态，需要做幂等
                 */
                applicationContext.publishEvent(new PayCallbackSuccessEvent(this, client, productId, userId, sourceFrom, resultMap));
                /*
                 * 通知微信
                 */
                SortedMap<String,String> reqMap = new TreeMap<>();
                reqMap.put("return_code", WXPayConstants.SUCCESS);
                reqMap.put("return_msg", "支付成功");
                String reqXml = WXPayUtil.mapToXml(reqMap);
                response.getWriter().write(reqXml);
            } else {
                LoggerUtil.error(MessageFormat.format("【微信】买家：{0} 于 {1} 支付金额 {2} 异步回调验签失败，订单编号：{3} 交易状态：{4}", openid, timeEnd, totalFee, orderId, returnCode));
                applicationContext.publishEvent(new PayCallbackFailEvent(this, client, productId, userId, resultMap));
                /*
                 * 通知微信
                 */
                SortedMap<String,String> reqMap = new TreeMap<>();
                reqMap.put("return_code", WXPayConstants.FAIL);
                reqMap.put("return_msg", "验签失败");
                String reqXml = WXPayUtil.mapToXml(reqMap);
                response.getWriter().write(reqXml);
            }
        }
    }
}
